#include "motrecreader.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <iostream>

#define MAX_BUFSZ	1024

static const char *obj2str_tab[] = {
	"ANY",
	"HAND",
	"LEFT HAND",
	"RIGHT HAND",
	"HEAD"
};

static const char *coo2str_tab[] = {
	"Face center",
	"Last time"
};

static const char *unit2str_tab[] = {
	"Face radius",
	"pixel",
	"Last unit"
};


void print_movement(Movement &mov) {
	std::cout << "Start time: " << mov.start_time << "s\t"
		<< "Duration: " << mov.duration << "s" << std::endl
		<< "Object: " << obj2str_tab[mov.object] << std::endl
		<< "Origin: " << coo2str_tab[mov.coord] << "\t"
		<< "Unit: " << unit2str_tab[mov.unit] << std::endl;
	for (std::list<std::pair<double, double> >::iterator iter = mov.points.begin();
			iter != mov.points.end(); iter++) {
		printf("(%.3f, %.3f)\n", iter->first, iter->second);
	}
	for (std::list<CvPoint>::iterator point_iter = mov.points_on_img.begin();
			point_iter != mov.points_on_img.end(); ++point_iter) {
		printf("\tPoint: (%d, %d)\n", point_iter->x, point_iter->y);
	}
}

MotionRecordReader::MotionRecordReader (std::string &motion_file) {
	MotionRecordReader(motion_file.c_str());
}
MotionRecordReader::MotionRecordReader (const char *motion_file) {
	_motion_file_name = std::string(motion_file);
	_motion_file_fp = fopen(_motion_file_name.c_str(), "r");
	_last_mov.start_time = -1;
	if (NULL == _motion_file_fp) {
		/* TODO throw an exception */
	}
}

MotionRecordReader::~MotionRecordReader () {
}

static int read_int(FILE *fp, int &out) {
	char buf[MAX_BUFSZ];
	char *ptr, *ret;
	memset(buf, 0, sizeof(buf));
	if (feof(fp))
		return -1;
	ret = fgets(buf, sizeof(buf), fp);
	if (NULL == ret)
		return -1;
	for (ptr = buf; !isdigit(*ptr) && *ptr != 0 && *ptr != '-'; ++ptr);
	out = atoi(ptr);
	return 0;
}

static int read_point2d(FILE *fp, double &x, double &y) {
	char buf[MAX_BUFSZ];
	char *ptr, *ret;
	memset(buf, 0, sizeof(buf));
	if (feof(fp))
		return -1;
	ret = fgets(buf, sizeof(buf), fp);
	if (NULL == ret)
		return -1;
	if (!strcmp(buf, "\n"))
		return 1;
	for (ptr = buf; !isdigit(*ptr) && *ptr != 0 && *ptr != '-'; ++ptr);
	if (0 == *ptr)
		return 1;
	x = atof(ptr);
	ptr = strchr(ptr, ',');
	for (++ptr; !isdigit(*ptr) && *ptr != 0 && *ptr != '-'; ++ptr);
	if (0 == *ptr)
		return 1;
	y = atof(ptr);
	return 0;
}

int MotionRecordReader::next_movement(Movement &mov) {
	/* One movement format:
	 * START TIME (int)
	 * DURATION (int)
	 * OBJECT (int)
	 * COORDINATION (int)
	 * UNIT (int)
	 * POINTS (double, double)
	 * ...
	 * blank line
	 */
	int int_val;
	double x,y;
	int ret;
	ret = read_int(_motion_file_fp, mov.start_time);
	if (ret)
		return -1;
	ret = read_int(_motion_file_fp, mov.duration);
	if (ret)
		return -1;
	ret = read_int(_motion_file_fp, mov.object);
	if (ret)
		return -1;
	ret = read_int(_motion_file_fp, mov.coord);
	if (ret)
		return -1;
	ret = read_int(_motion_file_fp, mov.unit);
	if (ret)
		return -1;
	for (ret = read_point2d(_motion_file_fp, x, y);
			0 == ret;
			ret = read_point2d(_motion_file_fp, x, y)) {
		mov.points.push_back(std::pair<double, double>(x,y));
	}
	return 0;
}

int MotionRecordReader::read_next_movement_list(
		std::list<Movement> &mov_list, 
		unsigned cur_time) {
	int nr_new_mov, ret;
	assert(_motion_file_fp != NULL);
	mov_list.clear();
	if (_last_mov.start_time < 0) {
		_last_mov.points.clear();
		ret = next_movement(_last_mov);
		if (ret)
			return -1;
	}
	if (_last_mov.start_time != (int)cur_time) {
		return 0;
	}
	nr_new_mov = 1;
	mov_list.push_back(_last_mov);
	_last_mov.points.clear();
	_last_mov.start_time = -1;
	for (ret = next_movement(_last_mov); 
			_last_mov.start_time == (int)cur_time && !ret;
			ret = next_movement(_last_mov)) {
		mov_list.push_back(_last_mov);
		++nr_new_mov;
		_last_mov.points.clear();
	}
	return nr_new_mov;
}

